﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using NBusiness.ESharp.Compiler;
using NBusiness.ESharp.Testing.Mocks;
using NBusiness.CodeDom;
using NBusiness.ESharp.Testing.Properties;
using NBusiness.CodeDom.Compiler;
using NBusiness.CodeDom.Services;

namespace NBusiness.ESharp.Testing
{
    [TestClass]
    internal class AccessRuleTests
    {
        [TestMethod]
        public void TestAccessRule1()
        {
            ESharpProvider provider = new ESharpProvider();
            MockBuildErrorService errorService = new MockBuildErrorService();
            MockTypeFinder typeFinderService = new MockTypeFinder();
            provider.SetService(typeof(IBuildErrorService), errorService);

            EntityRoot root = provider.GetParser().ParseFiles(
                new EntityFile ("Rules.Access1.es", Resources.Rules_Access1 ));

            Assert.AreEqual(0, errorService.Errors.Count);

            EntityFamily family = root.Families["Business"];
            Assert.IsNotNull(family);
            Assert.AreEqual(1, family.Entities.Count);

            Entity simple = family.Entities[0];
            Assert.IsNotNull(simple);
            Assert.AreEqual(2, simple.Fields.Count);
            Assert.AreEqual(4, simple.Rules.Count);

            EntityAccess a1 = simple.Rules[0] as EntityAccess;
            EntityAccess a2 = simple.Rules[1] as EntityAccess;
            EntityAccess a3 = simple.Rules[2] as EntityAccess;
            EntityAccess a4 = simple.Rules[3] as EntityAccess;

            //access deny mock * set Data;
            Assert.IsFalse(a1.Allow);            
            Assert.AreEqual("*", a1.Role);
            Assert.AreEqual(EntityAccessMethod.Set, a1.Method);
            Assert.AreEqual(simple.Fields[1], a1.Accessible);
            
            //access deny mock * get Data;
            Assert.IsFalse(a2.Allow);            
            Assert.AreEqual("*", a2.Role);
            Assert.AreEqual(EntityAccessMethod.Get, a2.Method);
            Assert.AreEqual(simple.Fields[1], a2.Accessible);
          
            //access allow mock * set Data;
            Assert.IsTrue(a3.Allow);            
            Assert.AreEqual("*", a1.Role);
            Assert.AreEqual(EntityAccessMethod.Set, a3.Method);
            Assert.AreEqual(simple.Fields[1], a3.Accessible);

            //access allow mock * get Data;
            Assert.IsTrue(a4.Allow);            
            Assert.AreEqual("*", a1.Role);
            Assert.AreEqual(EntityAccessMethod.Get, a4.Method);
            Assert.AreEqual(simple.Fields[1], a4.Accessible);
        }

        [TestMethod]
        public void TestAccessRule2()
        {
            ESharpProvider provider = new ESharpProvider();
            MockBuildErrorService errorService = new MockBuildErrorService();
            MockTypeFinder typeFinderService = new MockTypeFinder();
            provider.SetService(typeof(IBuildErrorService), errorService);

            EntityRoot root = provider.GetParser().ParseFiles(
                new EntityFile ("Rules.Access2.es", Resources.Rules_Access2 ));

            Assert.AreEqual(0, errorService.Errors.Count);
            
            EntityFamily family = root.Families["Business"];
            Assert.IsNotNull(family);
            Assert.AreEqual(2, family.Entities.Count);

            Entity a = family.Entities[0];
            Entity b = family.Entities[1];

            Assert.IsNotNull(a);
            Assert.IsNotNull(b);
            Assert.AreEqual("A", a.Name);
            Assert.AreEqual("B", b.Name);

            Assert.AreEqual(1, b.Relationships.Count);
            Assert.AreEqual(1, b.Rules.Count);
            Assert.IsInstanceOfType(b.Rules[0], typeof(EntityAccess));

            EntityAccess access = b.Rules[0] as EntityAccess;
            Assert.IsTrue(access.Allow);
            Assert.AreEqual(EntityAccessMethod.Get, access.Method);
            Assert.AreEqual("*", access.Role);
            Assert.AreSame(b.Relationships[0], access.Accessible);
        }

        [TestMethod]
        public void TestAccessRuleFail1()
        {
            ESharpProvider provider = new ESharpProvider();
            MockBuildErrorService errorService = new MockBuildErrorService();
            MockTypeFinder typeFinderService = new MockTypeFinder();
            provider.SetService(typeof(IBuildErrorService), errorService);

            EntityRoot root = provider.GetParser().ParseFiles(
                new EntityFile ("Rules.Access.Fail1.es", Resources.Rules_Access_Fail1 ));

            Assert.AreEqual(1, errorService.Errors.Count);
            EntityBuildError error = errorService.Errors[0];

            Assert.AreEqual("ES4004", error.ErrorCode);
            Assert.AreEqual(EntityBuildErrorType.Error, error.Type);
        }

        [TestMethod]
        public void TestAccessRuleFail2()
        {
            ESharpProvider provider = new ESharpProvider();
            MockBuildErrorService errorService = new MockBuildErrorService();
            MockTypeFinder typeFinderService = new MockTypeFinder();
            provider.SetService(typeof(IBuildErrorService), errorService);

            EntityRoot root = provider.GetParser().ParseFiles(
                new EntityFile ("Rules.Access.Fail2.es", Resources.Rules_Access_Fail2 ));

            Assert.AreEqual(1, errorService.Errors.Count);
            EntityBuildError error = errorService.Errors[0];

            Assert.AreEqual("ES4000", error.ErrorCode);
            Assert.AreEqual(EntityBuildErrorType.Error, error.Type);
        }
    }
}
